package com.db.utils;

import cn.hutool.core.util.ObjectUtil;
import com.db.query.QObject;
import com.db.query.Range;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;

/**
 * @author dzh
 * @since 2024/12/30
 */
public class QueryDslUtils {

    public static <T> Predicate predicate(Object param, Class<T> clazz) {
        QObject q = new QObject(clazz, param);
        return predicate(param, q);
    }

    public static Predicate predicate(Object param, QObject q) {
        Predicate qr = null;
        Field[] fields = FieldUtils.getAllFields(param.getClass());
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                String name = field.getName();
                Class<Comparable<?>> type = (Class<Comparable<?>>) field.getType();
                Object value = field.get(param);
                if (ObjectUtil.isNotEmpty(value)) {
                    if (value instanceof Range) {
                        Range<? extends Comparable> range = (Range) value;
                        Comparable<?> obj = ObjectUtil.defaultIfNull(range.getMinimum(), range.getMaximum());
                        if (obj == null) {
                            continue;
                        }
                        type = (Class<Comparable<?>>) obj.getClass();
                        qr = ExpressionUtils.and(qr, q.createComparable(name, type).between(range.getMinimum(), range.getMaximum()));
                    } else if (value instanceof Comparable) {
                        qr = ExpressionUtils.and(qr, q.createComparable(name, type).in(value));
                    } else if (value instanceof Collection) {
                        Collection<? extends Comparable<?>> collection = (Collection<? extends Comparable<?>>) value;
                        type = (Class<Comparable<?>>) collection.iterator().next().getClass();
                        qr = ExpressionUtils.and(qr, q.createComparable(name, type).in(collection));
                    } else if (value.getClass().isArray()) {
                        Collection<? extends Comparable<?>> collection = Arrays.stream(((Object[]) value)).map(item -> (Comparable<?>) item).collect(Collectors.toList());
                        type = (Class<Comparable<?>>) collection.iterator().next().getClass();
                        qr = ExpressionUtils.and(qr, q.createComparable(name, type).in(collection));
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return qr;
    }
}
